#pragma once
#include <string>
#include <array>
#include <locale>
#include <codecvt>
#include <boost/mp11.hpp>
#include <boost/describe/enum.hpp>
#include <boost/describe/enumerators.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/System/Vector3.hpp>
#include <SFML/Graphics/Rect.hpp>

template<class E>
std::string toString(E e)
{
    std::string string;
    boost::mp11::mp_for_each< boost::describe::describe_enumerators<E> >([&](auto U) {
        if (U.value == e)
            string = U.name;
    });
    return string;
}

template<class E>
E fromString(const std::string &string, E defaultE)
{
    E value = defaultE;
    boost::mp11::mp_for_each< boost::describe::describe_enumerators<E> >([&](auto U) {
        if (string == U.name)
            value = U.value;
    });
    return value;
}

template<class E>
struct enum_descriptor {
    E value;
    char const *name;
};

template<class E, template<class... T> class L, class... T>
constexpr std::array<enum_descriptor<E>, sizeof...(T)>
describe_enumerators_as_array_impl( L<T...> )
{
    return { { { T::value, T::name }... } };
}

template<class E>
constexpr auto describe_enumerators_as_array()
{
    return describe_enumerators_as_array_impl<E>( boost::describe::describe_enumerators<E>() );
}

template <typename T>
std::ostream &operator<<(std::ostream &os, sf::Vector2<T> v)
{
    os << v.x << "," << v.y;
    return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, sf::Vector3<T> v)
{
    os << v.x << "," << v.y<<","<<v.z;
    return os;
}

template <typename T>
inline std::ostream &operator<<(std::ostream &os, sf::Rect<T> r)
{
    os << r.left << ", " << r.top << "; " << r.width << ", " << r.height;
    return os;
}

inline std::wstring toWString(const std::string &input)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.from_bytes(input);
}

inline std::string toString(const std::wstring &input)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.to_bytes(input);
}

